//package cn.lingyangwl.agile.auth.constants.oauth2.support.core;
//
//import cn.hutool.core.util.StrUtil;
//import cn.hutool.extra.servlet.ServletUtil;
//import cn.lingyangwl.agile.auth.model.LockUser;
//import cn.lingyangwl.agile.auth.model.LoginContextHolder;
//import cn.lingyangwl.agile.auth.model.bo.CheckLoginUser;
//import cn.lingyangwl.agile.auth.constants.oauth2.service.MyUserDetailsService;
//import cn.lingyangwl.agile.auth.service.LoginUserService;
//import cn.lingyangwl.agile.model.constants.GrantTypeCons;
//import cn.lingyangwl.agile.model.enums.AuthErrorEnum;
//import cn.lingyangwl.framework.core.utils.servlet.ServletUtils;
//import cn.lingyangwl.framework.core.utils.spring.SpringUtils;
//import cn.lingyangwl.framework.tool.core.DateUtils;
//import cn.lingyangwl.framework.tool.core.exception.BizException;
//import lombok.SneakyThrows;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.core.Ordered;
//import org.springframework.security.authentication.BadCredentialsException;
//import org.springframework.security.authentication.InternalAuthenticationServiceException;
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
//import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
//import org.springframework.security.core.Authentication;
//import org.springframework.security.core.AuthenticationException;
//import org.springframework.security.core.userdetails.UserDetails;
//import org.springframework.security.core.userdetails.UserDetailsPasswordService;
//import org.springframework.security.core.userdetails.UserDetailsService;
//import org.springframework.security.core.userdetails.UsernameNotFoundException;
//import org.springframework.security.crypto.factory.PasswordEncoderFactories;
//import org.springframework.security.crypto.password.PasswordEncoder;
//import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
//import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;
//import org.springframework.util.Assert;
//
//import javax.servlet.http.HttpServletRequest;
//import java.util.Comparator;
//import java.util.Map;
//import java.util.Objects;
//import java.util.Optional;
//import java.util.function.Supplier;
//
///**
// * UserDetails 授权(eg: 验证密码是否正确), {@link MyUserDetailsService#loadUserByUsername(String)} 调用之后会调用
// * 本类
// * @author shenguangyang
// */
//@Slf4j
//public class MyDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
//
//	/**
//	 * The plaintext password used to perform PasswordEncoder#matches(CharSequence,
//	 * String)} on when the user is not found to avoid SEC-2056.
//	 */
//	private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
//
//	private final static BasicAuthenticationConverter basicConvert = new BasicAuthenticationConverter();
//
//	private PasswordEncoder passwordEncoder;
//
//	/**
//	 * The password used to perform {@link PasswordEncoder#matches(CharSequence, String)}
//	 * on when the user is not found to avoid SEC-2056. This is necessary, because some
//	 * {@link PasswordEncoder} implementations will short circuit if the password is not
//	 * in a valid format.
//	 */
//	private volatile String userNotFoundEncodedPassword;
//
//	private UserDetailsService userDetailsService;
//
//	private UserDetailsPasswordService userDetailsPasswordService;
//
//	private final LoginUserService loginUserService;
//
//	public MyDaoAuthenticationProvider() {
//		setMessageSource(SpringUtils.getBean("securityMessageSource"));
//		this.loginUserService = SpringUtils.getBean(LoginUserService.class);
//		setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
//	}
//
//	@Override
//	@SuppressWarnings("deprecation")
//	protected void additionalAuthenticationChecks(UserDetails userDetails,
//			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
//		// app 模式不用校验密码
//		String grantType = ServletUtils.getRequest().orElseThrow(() -> new BizException("request is null"))
//				.getParameter(OAuth2ParameterNames.GRANT_TYPE);
//		log.debug("oauth2 === grantType [{}]", grantType);
//		// 校验是否被锁定
//		LockUser lockUser = loginUserService.getLockUser(userDetails.getUsername());
//		if (Objects.nonNull(lockUser)) {
//			String unlockTime = DateUtils.distance(System.currentTimeMillis(), lockUser.getUnLockTimestamp(), true);
//			throw new ResourceAuthException(AuthErrorEnum.LOGIN_LOCKED, unlockTime);
//		}
//
//		if (StrUtil.equalsAny(grantType, GrantTypeCons.APP, GrantTypeCons.WX_MA, GrantTypeCons.WX_MP)) {
//			return;
//		}
//
//		if (authentication.getCredentials() == null) {
//			log.debug("Failed to authenticate since no credentials provided");
////			throw new BadCredentialsException(this.messages
////					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
//			throw new BadCredentialsException(AuthErrorEnum.USER_USERNAME_OR_PASSWORD_ERROR.getMessage());
//		}
//		// 开始校验用户
//		String presentedPassword = authentication.getCredentials().toString();
//		CheckLoginUser.of(userDetails.getUsername(), presentedPassword, LoginContextHolder.get().getLoginUser())
//				.isDeleted().isDisabled().matchPassword().throwError(ResourceAuthException::new);
//	}
//
//	/**
//	 * 获取UserDetails
//	 * @param username The username to retrieve
//	 * @param authentication The authentication request, which subclasses <em>may</em>
//	 * need to perform a binding-based retrieval of the <code>UserDetails</code>
//	 */
//	@SneakyThrows
//	@Override
//	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
//		prepareTimingAttackProtection();
//		HttpServletRequest request = ServletUtils.getRequest().orElseThrow(
//				(Supplier<Throwable>) () -> new InternalAuthenticationServiceException("web request is empty"));
//
//		Map<String, String> paramMap = ServletUtil.getParamMap(request);
//		String grantType = paramMap.get(OAuth2ParameterNames.GRANT_TYPE);
//		String clientId = paramMap.get(OAuth2ParameterNames.CLIENT_ID);
//
//		if (StrUtil.isBlank(clientId)) {
//			clientId = basicConvert.convert(request).getName();
//		}
//
//		Map<String, MyUserDetailsService> userDetailsServiceMap = SpringUtils
//				.getBeansOfType(MyUserDetailsService.class);
//
//		String finalClientId = clientId;
//		Optional<MyUserDetailsService> optional = userDetailsServiceMap.values().stream()
//				.filter(service -> service.support(finalClientId, grantType))
//				.max(Comparator.comparingInt(Ordered::getOrder));
//
//		if (!optional.isPresent()) {
//			throw new InternalAuthenticationServiceException("UserDetailsService error , not register");
//		}
//
//		try {
//			UserDetails loadedUser = optional.get().loadUserByUsername(username);
//			if (loadedUser == null) {
//				throw new InternalAuthenticationServiceException(
//						"UserDetailsService returned null, which is an interface contract violation");
//			}
//			return loadedUser;
//		} catch (UsernameNotFoundException ex) {
//			mitigateAgainstTimingAttack(authentication);
//			throw ex;
//		} catch (InternalAuthenticationServiceException | ResourceAuthException ex) {
//			throw ex;
//		} catch (Exception ex) {
//			log.error("error: ", ex);
//			throw new ResourceAuthException(AuthErrorEnum.FAIL);
//		}
//	}
//
//	@Override
//	protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
//			UserDetails user) {
//		boolean upgradeEncoding = this.userDetailsPasswordService != null
//				&& this.passwordEncoder.upgradeEncoding(user.getPassword());
//		if (upgradeEncoding) {
//			String presentedPassword = authentication.getCredentials().toString();
//			String newPassword = this.passwordEncoder.encode(presentedPassword);
//			user = this.userDetailsPasswordService.updatePassword(user, newPassword);
//		}
//		return super.createSuccessAuthentication(principal, authentication, user);
//	}
//
//	private void prepareTimingAttackProtection() {
//		if (this.userNotFoundEncodedPassword == null) {
//			this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
//		}
//	}
//
//	private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) {
//		if (authentication.getCredentials() != null) {
//			String presentedPassword = authentication.getCredentials().toString();
//			this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword);
//		}
//	}
//
//	/**
//	 * Sets the PasswordEncoder instance to be used to encode and validate passwords. If
//	 * not set, the password will be compared using
//	 * {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()}
//	 * @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
//	 * types.
//	 */
//	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
//		Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
//		this.passwordEncoder = passwordEncoder;
//		this.userNotFoundEncodedPassword = null;
//	}
//
//	protected PasswordEncoder getPasswordEncoder() {
//		return this.passwordEncoder;
//	}
//
//	public void setUserDetailsService(UserDetailsService userDetailsService) {
//		this.userDetailsService = userDetailsService;
//	}
//
//	protected UserDetailsService getUserDetailsService() {
//		return this.userDetailsService;
//	}
//
//	public void setUserDetailsPasswordService(UserDetailsPasswordService userDetailsPasswordService) {
//		this.userDetailsPasswordService = userDetailsPasswordService;
//	}
//
//}
